#include "Logic.h"
#include "Player.h"

/* Handle upkeep of battle. */
void Logic::doBattle()
{
  /* Count number of "stunned" players (deckless+handless) */
  int stunned = 0;
  for(int i = 0; i < table->players.size(); ++i)
    if(table->players.at(i).getArmy()->size() == 0 &&
       table->players.at(i).getHand()->size() == 0)
      ++stunned;
  /* Make sure all players have a card active. */
  if(table->activeCards.size() < table->players.size()-stunned) return;
  vector<Player*> tie = evaluateTable();
  /* If not a tie, just return winner. */
  if(tie.size() == 1)
  {
    table->soloMover = tie.at(0);
    giveBattleReward(tie.at(0));
  }
  /* WAR! */
  else
  {
    table->warTime = true;
    /* Tax involved players. */
    for(int i = 0; i < tie.size(); ++i)
    {
      taxPlayer(tie.at(i), 3);
      tie.at(i)->setWarFlag(true);
    }
  }
}

void Logic::doWar()
{
  /* Abort if there's a player who's not in yet. (ignore stunned players) */
  for(int i=0; i<table->players.size();++i)
    if(table->players.at(i).getWarFlag()      == true &&
       table->players.at(i).getArmy()->size() != 0    &&
       table->players.at(i).getHand()->size() != 0) return;
  /* See if we have another tie. */
  vector<Player*> tie = evaluateTable();
  /* If not a tie, just return winner. */
  if(tie.size() == 1)
  {
    giveBattleReward(tie.at(0));
    /* Peace! */
    table->warTime = false;
  }
  /* WAR (again!) */
  else
  {
    /* Tax involved players. */
    for(int i = 0; i < tie.size(); ++i)
    {
      taxPlayer(tie.at(i), 3);
      tie.at(i)->setWarFlag(true);
    }
  }
}

Deck Logic::getActives() 
{ 
  return table->activeCards; 
} 
int Logic::getGameWinner() 
{ 
  int foundPlayer = -1;
  /* Winning player is the only player with a deck. */
  for(int i = 0; i < table->players.size(); ++i)
  {
    if(!table->players.at(i).getIsVassal())
    {
      /* Fail if multiple winners still. */
      if(foundPlayer != -1)
      {
        return -1;
      }
      foundPlayer = i;
    }
  }
  /* If no issue, return winner. */
  return foundPlayer;
} 

vector<Player*> Logic::getMovingPlayers() 
{ 
  vector<Player*> result;
  /* Anyone with the flag can move during war. */
  if(table->warTime)
  {
    for(int i = 0; i < table->players.size(); ++i)
    {
      if(table->players.at(i).getWarFlag())
      {
        result.push_back(&table->players.at(i));
      }
    }
  }
  else
  {
    result.push_back(table->soloMover);
  }
  return result;
}

set<Player*> Logic::getWarringPlayers() 
{
  vector<Player*> winnersOfRound = evaluateTable();
  if(winnersOfRound.size() > 1){
	return set<Player*>  (winnersOfRound.begin(), winnersOfRound.end());
  }
  else{
        return set<Player*>();
  }  
}
 
void Logic::processSoloMove()
{
  /* Find soloMover. */
  for(int i = 0; i < table->players.size(); ++i)
  {
    if(&table->players.at(i) == table->soloMover)
    {
      /* Moves cost cards. */
      taxPlayer(table->soloMover, 1); 
      int offset = 1;
      while(table->players.at(i+offset).getArmy()->size() == 0 &&
            table->players.at(i+offset).getHand()->size() == 0 )
        ++offset;
      /* Move to next player */
      table->soloMover = &table->players.at((i+offset)%(table->players.size()));
    }
  }
}
void Logic::removeSpoils() 
{ 
  /* Draw all cards. */
  table->spoilsPile.draw(table->spoilsPile.size());
} 

void Logic::setActive(Card* card, Player* player) 
{ 
  /* NEEDS TESTING */ 
  for(int i = 0; i < table->activeCards.size(); ++i) 
  { 
    if(table->activeCards.at(i)->getOwner() == player) 
    { 
      /* Move card to the pillage pile. */
      table->pillagePile.add(table->activeCards.at(i));
      /* Replace the original. */
      table->activeCards.replace(i, card);
      return;
    } 
  } 
  table->activeCards.add(card);
}
void Logic::setTable(Table* t) 
{ 
  table = t;
} 
void Logic::taxPlayer(Player* taxMe, int numberOfCards) 
{
  /* Vassals get their czar to pay tax for them. */
  if(taxMe->getIsVassal())
    taxMe->getOwner()->getArmy()->transfer(numberOfCards, &table->spoilsPile);
  else
    taxMe->getArmy()->transfer(numberOfCards, &table->spoilsPile);
} 

void Logic::updateActiveCard(){
vector<Player*> movers = getMovingPlayers();
  for(int i = 0; i < movers.size(); ++i)
  {
    /* You can make a move!  Accept the move! */
    if(movers.at(i)->getMoveCard() != NULL)
    {
      /* Jokers clear the spoils pile. */
      if(movers.at(i)->getMoveCard()->getRank() == joker) removeSpoils();
      /* Update the active cards. */
      setActive(movers.at(i)->getMoveCard(), movers.at(i));
      movers.at(i)->setWarFlag(false);
      movers.at(i)->setMoveCard(NULL);
    }
  }
}


void Logic::checkConflict(){
	/* If soloMover has made their move... */
    if(table->soloMover->getMoveCard() != NULL)
    {
      /* increment solomover and tax. */
      processSoloMove();
      /* See if the battle gets anywhere. */
      doBattle();
    }
}


void Logic::freeVassals(){

  for(int i = 0; i < table->players.size(); ++i)
    {
      /* If vassal is defeated... You're free again. */
      if(table->players.at(i).getOwner()->getArmy()->size() == 0 &&
         table->players.at(i).getOwner()->getHand()->size() == 0)
        table->players.at(i).setOwner(NULL);
    }

}

void Logic::findBattleWinner(int index, int iteration){
	int czarIndex = index;
	int i = iteration;
	while(&table->players.at(czarIndex) != table->soloMover) czarIndex++;
        /* Search until you find a non-vassal player with an army. */
        for(int failCounter = 0; failCounter < 10; failCounter++)
	{
	  Player* canidate = &table->players.at(czarIndex);
	  /* If you're a vassal, your czar is the canidate for the new vassal */
	  if(canidate->getIsVassal()) canidate = canidate->getOwner();
	  /* If this canidate can support a vassal, give it! */
	  if(canidate->getArmy()->size() > 0)
	  {
            table->players.at(i).setOwner(canidate);
            canidate->addVassal(&table->players.at(i));
	    break;
	  }
	}

}

void Logic::reviveVassals(){
for(int i = 0; i < table->players.size(); ++i)
{
	if(table->players.at(i).getArmy()->size() == 0 &&
         table->players.at(i).getHand()->size() == 0)
      {
	/* Find the winner of the battle. */
		int czarIndex = 0;
		findBattleWinner(czarIndex, i);
	/* Give the vassal to the player. */
        table->players.at(i).setOwner(&table->players.at(czarIndex));
		table->players.at(czarIndex).addVassal(&table->players.at(i));
      }
}
}


bool Logic::doTick() 
{
  updateActiveCard();
  
  if(!table->warTime)
  {
  	checkConflict();
  }
  else
  {
    doWar();
  }
  /* End of round clean-up */
  if(table->activeCards.size() == 0)
  {
   	freeVassals();
    /* Update each player. */
    reviveVassals();
    /*Feed*/
    
  }
}


vector<Player*> Logic::handleAce(vector<Player*> result_vector){

vector<Player*> result = result_vector;

if(table->warTime)
  {
    /* Search pile for aces, put owners in result. */
    for(int i = 0; i < table->activeCards.size(); ++i)
    {
      if(table->activeCards.at(i)->getRank() == ace)
      {
        result.push_back(table->activeCards.at(i)->getOwner());
        return result;
      }
      /* Jokers make aces low. */
      else if(table->activeCards.at(i)->getRank() == joker)
      {
        result.clear();
        return result;
      }
    }
 }
 
}
 

vector<Player*> Logic::getPlayersWithBestCard(vector<Player*> result_vector){

vector<Player*> result = result_vector;

  Card* best = table->activeCards.at(table->activeCards.size()-1);
  /* Iterate backwards until you find one that doesn't tie with best. */
  for(int i = table->activeCards.size()-1; i >= 0; --i)
  {
    if(best->compareCard(*table->activeCards.at(i)) == 0)
    {
      result.push_back(table->activeCards.at(i)->getOwner());
      return result;
    }
    else return result;
  }

}

/* Returns the set of tieing players. */
vector<Player*> Logic::evaluateTable() 
{
  vector<Player*> result;
  /* Do ace check if at war. */
  result = handleAce(result);
  /* If at least one ace in pile, return result. */
  if(!result.empty()) return result;  
  /* Sort activeCards deck */
  table->activeCards.sort();
  /* Get best card in deck. */
  result = getPlayersWithBestCard(result);  
  /* Return vector. */
  return result;
} 
void Logic::giveBattleReward(Player* winner) 
{
  /*add all cards on table to player's deck*/
  Deck* reward;
  reward->add(&table->pillagePile);
  reward->add(&table->activeCards);
  reward->shuffle();
  /* Vassals pay tribute to their czar. */
  if(winner->getIsVassal()) winner->getOwner()->getArmy()->add(reward);
  /* Czars keep their earnings. */
  else winner->getArmy()->add(reward);
}
